let
multiReplace= (InputText as text,tOldNew as table)as text=>
let
//Use List.Generate() to do the replacements
DoReplacement = List.Generate(
()=> [Counter=0, MyText=InputText],
each [Counter]<Table.RowCount(tOldNew),
each [Counter=[Counter]+1,
MyText=Text.Replace(
[MyText],
tOldNew[Old]{Counter},
tOldNew[New]{Counter}
)
],
each [MyText]),
//Return the last item in the list that
//List.Generate() returns
GetLastValue = List.Last(DoReplacement)
in
GetLastValue
in
multiReplace
Unlawful Nerdy Knowledge
Thursday, February 6, 2020
Powerquery multi replace
Function to replace multiple text strings based on a table with "Old" and "New" Columns.
For powerquery / m
Thursday, October 1, 2015
Claimtree tool
Hopefully it's self explanatory. Don't sleep on the allowance tools, that's pretty much all I use it for nowadays. It renumbers claim and can autofill the issueclassification in IFW.
Here it is.
Friday, July 31, 2015
Useful macros for examiners
First some helper functions we need
Working with numbers: you'll need these for the numbering rejections macros below, but they are also useful themselves. Formatselection will turn "1 5 3 2 4" into "1-5" much like the boxes on a 326 do. removeNumberSelection() will take the selection 1-5 and ask you what numbers to remove. If you say "3 4" it will change it to "1-2 and 5"
You also need to add this class file and name it NumberList
Add this macro and a button to always put your signature in the box at the bottom of an action. Also won't sign if there are still unaccepted changes
Add classy line numbers to replace OACS's broken paragraph numbering
Add this as well if you want to always remember to do this when you close the document, should only ask when you are working on your own OACS correspondence
For making amendments, turn on track changes, make changes, and then run this macro. The tracked changes will change to 1.121 compliant markup.
ok so this is still a work in progress, but I've been working on pulling numbers automatically out my actions into the statements of rejection. updateNum() will update the numbering in hidden text at the begining of each section. if a 102 or 103 rejection statement is right above the marker, it will bold and insert the numbers in to that statement. You may have to go into options and make sure that hidden text is visible. the invisible flags STARTREJ and ENDREJ will border each section. To eliminate typos and anyother problems select an empty paragraph or a group of claims, and run surroundSelRej(). That will insert the markers.
Copy table rows from the IDS tab in edan (ctrl+s) and run this to paste in a list of IDS dates
this will turn on all the buttons in oacs in the event they are all disabled for no reason, I don't think this will work the buttons in the ribbon, but the old command bar still exists on the Developer ribbon
Put the right obviousness tatement in the rejection
Public Function isOacs() As Boolean
isOacs = ActiveDocument.AttachedTemplate Like "oacs*"
End Function
Public Function isOacsForm()
isOacsForm = Left(ActiveDocument.name, 3) Like "PTO" Or Left(ActiveDocument.name, 3) Like "IFW"
End Function
Public Function hasMarkup()
hasMarkup = (ActiveDocument.Comments.Count > 0) Or (ActiveDocument.Revisions.Count > 0)
End Function
Function FindCommandBar(name As String) As CommandBar
For Each FindCommandBar In CommandBars
'If Not FindCommandBar.name Is Empty Then
If FindCommandBar.name Like name Then Exit Function
Next FindCommandBar
Set FindCommandBar = Nothing
End Function
Function FindCommandButton(bar As CommandBar, name As String) As CommandBarControl
Dim combo As CommandBarComboBox
For Each FindCommandButton In bar.Controls
On Error Resume Next
If unAmp(FindCommandButton.Caption) Like name Then Exit Function
Next FindCommandButton
Set FindCommandButton = Nothing
Exit Function
End Function
Working with numbers: you'll need these for the numbering rejections macros below, but they are also useful themselves. Formatselection will turn "1 5 3 2 4" into "1-5" much like the boxes on a 326 do. removeNumberSelection() will take the selection 1-5 and ask you what numbers to remove. If you say "3 4" it will change it to "1-2 and 5"
Function numbers2Collection(strInput As String) As Collection
'Dim groups As Integer
'Dim strInput As String
'strInput = "2 5 6,4, 10-13 and 1"
Dim reg As New RegExp
'Dim addString As String
Dim i As Integer, c As Integer
Dim matches As MatchCollection
Dim m As match
Dim allNums As String
Dim firstLast() As String
'Dim firstInGroup As Integer
'Dim lastInGroup As Integer
Dim sorted As New Collection
reg.Global = True
reg.Pattern = "\d+-\d+"
Set matches = reg.Execute(strInput)
Dim mi As Integer
For mi = matches.Count - 1 To 0 Step -1
Set m = matches(mi)
allNums = ""
firstLast = Split(m.Value, "-")
For i = firstLast(0) To firstLast(1)
allNums = allNums & " " & i
Next i
strInput = Left(strInput, m.FirstIndex) & allNums & Mid(strInput, m.FirstIndex + m.length + 1)
Next mi
reg.Pattern = "\d+"
Set matches = reg.Execute(strInput)
sorted.Add CInt(matches(0).Value)
For i = 1 To matches.Count - 1
For c = 1 To sorted.Count
If CInt(matches(i).Value) < sorted(c) Then
sorted.Add CInt(matches(i).Value), Before:=c
Exit For
ElseIf c = sorted.Count Then
sorted.Add CInt(matches(i).Value), After:=c
Exit For
End If
Next c
Next i
Set numbers2Collection = sorted
End Function
Function formatNumbers(strInput As String) As String
Dim groups As Integer
'Dim strInput As String
'strInput = "2 5 6,4, 10-13 and 1"
'Dim reg As New regexp
Dim addString As String
'Dim i As Integer
Dim c As Integer
'Dim matches As MatchCollection
'Dim m As match
'Dim allNums As String
Dim firstLast() As String
Dim firstInGroup As Integer
Dim lastInGroup As Integer
Dim sorted As Collection
Set sorted = numbers2Collection(strInput)
'at this point all numbers are sorted and in the collection
c = sorted.Count
Do Until c <= 0
firstInGroup = sorted(c)
lastInGroup = sorted(c)
c = c - 1
If c > 0 Then
Do While firstInGroup - 1 = sorted(c)
firstInGroup = sorted(c)
c = c - 1
If c = 0 Then Exit Do
Loop
End If
' add the addstring to the total string
If firstInGroup = lastInGroup Then addString = firstInGroup Else addString = firstInGroup & "-" & lastInGroup
Select Case groups
Case 0
formatNumbers = addString
Case 1
formatNumbers = addString & " and " & formatNumbers
Case Else
formatNumbers = addString & ", " & formatNumbers
End Select
groups = groups + 1
Loop
Exit Function
End Function
Sub formatSelection()
Dim list As New NumberList
list.Create Selection.Text
Selection.Text = list.toString
End Sub
Sub removeNumberSelection()
Dim sorted As Collection
Set sorted = numbers2Collection(Selection.Text)
Dim strDel As String
strDel = InputBox("What claims do you want to remove from the selection?")
If strDel = "" Then Exit Sub
Dim colDel As Collection
Set colDel = numbers2Collection(strDel)
Dim i As Integer
Dim find As Integer
For i = 1 To colDel.Count
find = BinarySearchInt(sorted, colDel(i))
If find > 0 Then sorted.Remove find
Next i
Dim out As String
out = ""
For i = 1 To sorted.Count
out = out & " " & sorted(i)
Next i
Selection.Text = formatNumbers(out)
End Sub
Function BinarySearchInt(arr As Collection, ByVal search As Integer) As Long
Dim Index As Long
Dim first As Long
Dim last As Long
Dim middle As Long
Dim inverseOrder As Boolean
first = 1
last = arr.Count
' deduct direction of sorting
inverseOrder = (arr(first) > arr(last))
' assume searches failed
BinarySearchInt = first - 1
Do
middle = (first + last) \ 2
If arr(middle) = search Then
BinarySearchInt = middle
Exit Do
ElseIf ((arr(middle) < search) Xor inverseOrder) Then
first = middle + 1
Else
last = middle - 1
End If
Loop Until first > last
End Function
You also need to add this class file and name it NumberList
Option Explicit
Private sorted As Collection
Public Sub Create(strInput As String)
'Dim groups As Integer
'Dim strInput As String
'strInput = "2 5 6,4, 10-13 and 1"
Dim reg As New RegExp
'Dim addString As String
Dim i As Integer, c As Integer
Dim matches As MatchCollection
Dim m As match
Dim allNums As String
Dim firstLast() As String
'Dim firstInGroup As Integer
'Dim lastInGroup As Integer
Set sorted = New Collection
reg.Global = True
reg.Pattern = "\d+-\d+"
Set matches = reg.Execute(strInput)
For Each m In matches
allNums = ""
firstLast = Split(m.Value, "-")
For i = firstLast(0) To firstLast(1)
allNums = allNums & " " & i
Next i
strInput = Replace(strInput, m.Value, allNums)
Next m
reg.Pattern = "\d+"
Set matches = reg.Execute(strInput)
sorted.Add CInt(matches(0).Value)
For i = 1 To matches.Count - 1
For c = 1 To sorted.Count
If CInt(matches(i).Value) < sorted(c) Then
sorted.Add CInt(matches(i).Value), Before:=c
Exit For
ElseIf c = sorted.Count Then
sorted.Add CInt(matches(i).Value), After:=c
Exit For
End If
Next c
Next i
End Sub
Function toString() As String
Dim groups As Integer
'Dim strInput As String
'strInput = "2 5 6,4, 10-13 and 1"
'Dim reg As New regexp
Dim addString As String
'Dim i As Integer
Dim c As Integer
'Dim matches As MatchCollection
'Dim m As match
'Dim allNums As String
Dim firstLast() As String
Dim firstInGroup As Integer
Dim lastInGroup As Integer
' Dim sorted As Collection
Dim formatNumbers As String
' Set sorted = numbers2Collection(strInput)
'at this point all numbers are sorted and in the collection
c = sorted.Count
Do Until c <= 0
firstInGroup = sorted(c)
lastInGroup = sorted(c)
c = c - 1
If c > 0 Then
Do While firstInGroup - 1 = sorted(c)
firstInGroup = sorted(c)
c = c - 1
If c = 0 Then Exit Do
Loop
End If
' add the addstring to the total string
If firstInGroup = lastInGroup Then addString = firstInGroup Else addString = firstInGroup & "-" & lastInGroup
Select Case groups
Case 0
formatNumbers = addString
Case 1
formatNumbers = addString & " and " & formatNumbers
Case Else
formatNumbers = addString & ", " & formatNumbers
End Select
groups = groups + 1
Loop
toString = formatNumbers
Exit Function
End Function
Public Property Get length() As Integer
sorted.Count
End Property
Add this macro and a button to always put your signature in the box at the bottom of an action. Also won't sign if there are still unaccepted changes
Public Sub signRightPlace()
Dim btnSig As Office.CommandBarButton
Set btnSig = FindCommandButton(FindCommandBar("OACS"), "eSignature")
If Not hasMarkup Then
If Left(ActiveDocument.name, 3) Like "PTO" Or Left(ActiveDocument.name, 3) Like "IFW" Then
btnSig.Execute
Else
Dim sigTable As Word.Table
Dim endOfDoc As Range
Set endOfDoc = ActiveDocument.Range(InStr(ActiveDocument.Range.Text, "For more information about the PAIR system, see http://pair-direct.uspto.gov"), ActiveDocument.Range.End)
If endOfDoc.Tables.Count = 1 Then
Set sigTable = endOfDoc.Tables(1)
If sigTable.Rows.Count <> 1 Or sigTable.Columns.Count <> 2 Then GoTo stupid
Else
Set endOfDoc = endOfDoc.Paragraphs(1).Range
Set sigTable = endOfDoc.Tables.Add(endOfDoc, 1, 2)
sigTable.Range.ParagraphFormat.LineSpacingRule = wdLineSpaceSingle
End If
If ActiveWindow.View = wdWebView Then ActiveWindow.View = wdPrintView
sigTable.Cell(1, 2).Range.Select
ActiveWindow.ScrollIntoView Selection
btnSig.Execute
End If
Else
MsgBox "has markup"
End If
Exit Sub
stupid:
MsgBox "really?"
End Sub
Open current application in eDanSub edanOpen()
Dim fs As New FileSystemObject
Dim f As Folder
Set f = fs.GetFolder(ActiveDocument.Path)
Set f = f.ParentFolder
Dim appNo As String
'now we've got the last three digits for network OR the whole thing
appNo = getCurrentAppNum
ChDrive "c"
ChDir "C:\Program Files (x86)\eDAN"
Debug.Print CurDir
Shell "eDAN_API.cmd ""edan:openapp(appid=""" & appNo & """)"""
End Sub
Public Function getCurrentAppNum()
Dim fs As New FileSystemObject
Dim f As Folder
Set f = fs.GetFolder(ActiveDocument.Path)
Set f = f.ParentFolder
If Len(f.name) = 3 Then
getCurrentAppNum = f.ParentFolder.ParentFolder.name & f.ParentFolder.name & f.name
ElseIf Len(f.name) = 8 Then
getCurrentAppNum = f.name
Else
Err.Raise vbError + 2, , "can't program"
End If
End Function
Add classy line numbers to replace OACS's broken paragraph numbering
Sub OacsNum2LineNums()
Dim p As Paragraph
For Each p In ActiveDocument.Paragraphs
If p.Range.ListFormat.ListType <> wdListNoNumbering Then
p.Range.ListFormat.RemoveNumbers
p.Range.InsertBefore vbTab
End If
Next p
With ActiveDocument.PageSetup.LineNumbering
.Active = True
.CountBy = 5
.RestartMode = wdRestartPage
End With
End Sub
Add this as well if you want to always remember to do this when you close the document, should only ask when you are working on your own OACS correspondence
Sub autoclose()
If isOacs Then
If Not isOacsForm Then
If ActiveDocument.Path Like "c:\*" Then
If ActiveDocument.PageSetup.LineNumbering.Active = False Then
Dim r As VbMsgBoxResult
r = MsgBox("No line numbers detected. Run Oacs2LineNumbers?", vbYesNo, "Close Doc")
If r = vbYes Then OacsNum2LineNums
End If
End If
End If
End If
End Sub
For making amendments, turn on track changes, make changes, and then run this macro. The tracked changes will change to 1.121 compliant markup.
Sub amd()
Const rule121 = 5
Dim doc As Document
Dim rev As Revision
Dim tRange As Range
Set doc = ActiveDocument
doc.TrackRevisions = False
For Each rev In doc.Revisions
Select Case rev.Type
'Only include insertions and deletions
Case wdRevisionInsert
rev.Range.Underline = wdUnderlineDouble
rev.Range.Bold = True
rev.Range.Font.Color = wdColorRed
rev.accept
Case wdRevisionDelete
If rev.Range.Characters.Count > rule121 Then
rev.Range.Font.StrikeThrough = True
rev.Range.Font.Color = wdColorBlue
rev.Reject
Else
Set tRange = rev.Range
rev.Reject
'tRange.Font.Color = wdColorBlue
tRange.InsertAfter "]]"
tRange.InsertBefore "[["
tRange.Font.Color = wdColorBlue
End If
End Select
Next rev
Set tRange = Nothing
Set doc = Nothing
Set rev = Nothing
End Sub
ok so this is still a work in progress, but I've been working on pulling numbers automatically out my actions into the statements of rejection. updateNum() will update the numbering in hidden text at the begining of each section. if a 102 or 103 rejection statement is right above the marker, it will bold and insert the numbers in to that statement. You may have to go into options and make sure that hidden text is visible. the invisible flags STARTREJ and ENDREJ will border each section. To eliminate typos and anyother problems select an empty paragraph or a group of claims, and run surroundSelRej(). That will insert the markers.
Public Sub getNumbers()
Call getNumbersR(Selection.Range)
End Sub
Public Sub updateNums()
Dim p As Integer, start As Long, strList As String
p = 1
Dim first As Boolean, firstStart As Long
first = True
Do While p <= ActiveDocument.Paragraphs.Count
If ActiveDocument.Paragraphs.Item(p).Range.Font.Hidden = True Then
If ActiveDocument.Range(ActiveDocument.Paragraphs.Item(p).Range.start, ActiveDocument.Paragraphs.Item(p).Range.start + Len(startFlag)) = startFlag Then
start = ActiveDocument.Paragraphs.Item(p).Range.start
If first Then
firstStart = start
first = False
End If
Do Until ActiveDocument.Paragraphs.Item(p).Range.Font.Hidden = True And ActiveDocument.Paragraphs.Item(p).Range.Text = endFlag & vbCr
If p > ActiveDocument.Paragraphs.Count Then Exit Sub
p = p + 1
Loop
strList = strList & " " & getNumbersR(ActiveDocument.Range(start, ActiveDocument.Paragraphs.Item(p).Range.start))
End If
End If
p = p + 1: Loop
Dim firstP As Paragraph
p = 1
Do While p <= ActiveDocument.Paragraphs.Count
If ActiveDocument.Paragraphs.Item(p).Range.Font.Hidden = True Then
If ActiveDocument.Range(ActiveDocument.Paragraphs.Item(p).Range.start, ActiveDocument.Paragraphs.Item(p).Range.start + Len(startFlag)) = startFlag Then
Set firstP = ActiveDocument.Paragraphs.Item(p)
GoTo first
End If
End If
p = p + 1: Loop
Err.Raise vbError + 2, , "StartRej not found"
Exit Sub
first:
If firstP.Previous.Range.Font.Hidden = True And firstP.Previous.Range.Text Like allFlag & "*" & vbCr Then
firstP.Previous.Range.Text = allFlag & " " & formatNumbers(strList) & vbCr
Else
firstP.Range.InsertBefore (allFlag & " " & formatNumbers(strList) & vbCr)
End If
End Sub
Public Function getNumbersR(r As Range) As String
'takes a selection
Dim p As Paragraph
Dim i As Integer
Dim nums As String
nums = ""
On Error GoTo ErrorHandler
ActiveDocument.ActiveWindow.View.ShowFirstLineOnly = False
' If Not Selection.Words(1) Like "Regarding " Then
' MsgBox "Error"
' Exit Sub
' End If
' For Each p In Selection.Paragraphs
' If p.Range.Words(1) Like "Regarding " Then
' i = 7
' Do While (Asc(p.Range.Words(i).Characters(1)) >= Asc("0")) And (Asc(p.Range.Words(i).Characters(1)) <= Asc("9"))
' nums = nums & p.Range.Words(i).Text & " "
' i = i + 2
' Loop
' End If
' Next p
Dim reg As RegExp
Dim mMatch As match
Set reg = New RegExp
reg.Global = True
reg.MultiLine = True
reg.IgnoreCase = True
reg.Pattern = "^(\t)*Regarding (?:(?:in)?dependent )?claim(?:s|(?:\(s\)))? ((?:\d+[-\s,]*)+)( and [\d-]+)?,"
For Each mMatch In reg.Execute(r.Text)
nums = nums & " " & mMatch.SubMatches(0) & mMatch.SubMatches(1) & mMatch.SubMatches(2)
Next mMatch
reg.Pattern = "Claim([s\s\?]*(?:[-,\*\d\s]|and)+\s*(?:is|are)*)\s*rejected"
'ActiveDocument.ActiveWindow.View.ShowFirstLineOnly = True
'ActiveWindow.ScrollIntoView r.Characters(1), True
Dim list As New NumberList
list.Create nums
Dim strList As String
strList = list.toString
Dim matches As MatchCollection
Dim fpPara As Word.Range
Set fpPara = r.Paragraphs(1).Previous.Range
If fpPara.Text Like allFlag & "*" & vbCr And fpPara.Font.Hidden = True Then
Set fpPara = fpPara.Previous(WdUnits.wdParagraph)
End If
Set matches = reg.Execute(fpPara.Text)
Dim one As Boolean
reg.Pattern = "\D"
one = Not reg.test(strList)
If matches.Count = 1 Then
'add to fp
fpPara.SetRange fpPara.start + InStr(fpPara.Text, matches(0).SubMatches(0)) - 1, fpPara.start + InStr(fpPara.Text, "rejected") - 1
fpPara.Text = IIf(one, " ", "s ") & strList & IIf(one, " is ", " are ")
fpPara.Paragraphs(1).Range.Bold = True
If ActiveDocument.Range(r.start, r.start + Len(startFlag)) = startFlag Then
r.Paragraphs(1).Range.Text = startFlag & " " & strList & vbCr
End If
Else
If ActiveDocument.Range(r.start, r.start + Len(startFlag)) = startFlag Then
r.Paragraphs(1).Range.Text = startFlag & " " & strList & vbCr
Else
r.InsertParagraphBefore
'Selection.InsertBefore formatNumbers(nums) & " "
r.InsertBefore strList & " "
End If
End If
getNumbersR = strList
Exit Function
ErrorHandler:
If Err.Number = 6028 Then
fpPara.Fields(1).Delete
Err.Clear
Resume
End If
If Err.Number = 4605 Then Resume Next Else MsgBox Err.Description
Resume
End Function
Public Sub surroundSelRej()
Dim r As Range
Set r = Selection.Range
r.Paragraphs(1).Range.InsertBefore (startFlag & vbCr)
r.InsertAfter (vbCr & vbCr)
With r.Paragraphs(1).Range
.Text = startFlag & vbCr
.Font.Hidden = True
End With
With r.Paragraphs(r.Paragraphs.Count - 1).Range
.Text = endFlag & vbCr
.Font.Hidden = True
End With
End Sub
Public Sub getNumbersRej()
'takes a selection
Dim p As Paragraph
Dim i As Integer
Dim nums As String
nums = ""
On Error GoTo ErrorHandler
ActiveDocument.ActiveWindow.View.ShowFirstLineOnly = False
' If Not Selection.Words(1) Like "Regarding " Then
' MsgBox "Error"
' Exit Sub
' End If
' For Each p In Selection.Paragraphs
' If p.Range.Words(1) Like "Regarding " Then
' i = 7
' Do While (Asc(p.Range.Words(i).Characters(1)) >= Asc("0")) And (Asc(p.Range.Words(i).Characters(1)) <= Asc("9"))
' nums = nums & p.Range.Words(i).Text & " "
' i = i + 2
' Loop
' End If
' Next p
Dim reg As RegExp
Dim mMatch As match
Set reg = New RegExp
reg.Global = True
reg.MultiLine = True
reg.IgnoreCase = False
reg.Pattern = "Claim[s\s]*((?:[-,\d\s]|and)+)\s*(?:is|are)*\s*rejected"
For Each mMatch In reg.Execute(Selection.Range.Text)
nums = nums & " " & mMatch.SubMatches(0)
Next mMatch
' Selection.InsertParagraphBefore
' Selection.InsertBefore formatNumbers(nums) & " "
' ActiveDocument.ActiveWindow.View.ShowFirstLineOnly = True
' ActiveWindow.ScrollIntoView Selection, True
Dim r As VbMsgBoxResult
Dim result As String
result = formatNumbers(nums)
r = MsgBox(result, vbOKCancel + vbQuestion, "Copy to Clipboard?")
If r = vbOK Then
Dim d As New MSForms.DataObject
d.SetText result
d.PutInClipboard
End If
Exit Sub
ErrorHandler:
If Err.Number = 4605 Then Resume Next Else MsgBox Err.Description
Resume
End Sub
Copy table rows from the IDS tab in edan (ctrl+s) and run this to paste in a list of IDS dates
Sub IDSfromEdan()
Const dataPattern = "(\d{2}/){2}\d{4}(?=\t)"
Dim reg As VBScript_RegExp_55.RegExp
Dim matches As MatchCollection
Dim data As DataObject
Dim regI As Integer
Dim strIDS As String
Set reg = New RegExp
Set data = New DataObject
reg.Global = True
reg.Pattern = dataPattern
data.GetFromClipboard
Set matches = reg.Execute(data.GetText)
For regI = matches.Count - 2 To 0 Step -2
strIDS = strIDS & matches(regI) & ", "
Next regI
strIDS = Left(strIDS, IIf(Len(strIDS) < 2, 0, Len(strIDS) - 2))
If matches.Count > 1 Then strIDS = Left(strIDS, InStrRev(strIDS, ", ")) & Replace(strIDS, ", ", " and ", InStrRev(strIDS, ", "))
Selection = strIDS
End Sub
Not sure how well this or the previous macro will work if your columns are setup differently then mine, but copy a whole row of a patent in the list of results in EAST and run this to paste in a nicely formatted patent number, name and date.
Const patentPattern = "[\s^](US (?:(\d{11})|(\d{7,8})) \w\d*)[\s$]"
Const patenteePattern = "[\t^]([-\w]+)[,;](?:(?:[^\t]*?( et al\.))|(?:[^\t]*?[\t$]))"
Const datePattern = "[\s^](\d{4})(\d\d)(\d\d)[\s$]"
Dim reg As New VBScript_RegExp_55.RegExp
'Set reg = CreateObject("VBScript_RegExp_55.regexp")
Dim results As MatchCollection
Dim result As VBScript_RegExp_55.match
Dim data As DataObject
Dim east As String
Dim patent As String
Dim patentee As String
Dim pubDate As String
Set data = New DataObject
On Error GoTo leave
data.GetFromClipboard
east = data.GetText
reg.Pattern = patentPattern
reg.Global = False
Set result = reg.Execute(east).Item(0)
'patent = result.SubMatches(0)
If result.SubMatches(1) = Empty Then
'patent
patent = Format(result.SubMatches(2), "standard")
patent = Left(patent, Len(patent) - 3)
patent = Replace(result.SubMatches(0), result.SubMatches(2), patent)
Else 'pgpub
patent = Left(result.SubMatches(1), 4) & "/" & Mid(result.SubMatches(1), 5)
patent = Replace(result.SubMatches(0), result.SubMatches(1), patent)
End If
reg.Pattern = patenteePattern
reg.Global = False
' Set results = reg.Execute(east)
' If results.Count = 2 Then
' If results(0).Length < results(1).Length Then Set result = results(0) Else Set result = results(1)
' Else
' Set result = results.Item(0)
'
' End If
Set result = reg.Execute(east).Item(0)
patentee = result.SubMatches(0) & result.SubMatches(1)
patent = Replace(patent, " ", Chr(160))
reg.Pattern = datePattern
reg.Global = False
Set result = reg.Execute(east).Item(0)
pubDate = result.SubMatches(1) & "/" & result.SubMatches(2) & "/" & result.SubMatches(0)
Selection = patentee & " (" & patent & ", " & pubDate & ")"
Selection.MoveRight
leave:
End Sub
this will turn on all the buttons in oacs in the event they are all disabled for no reason, I don't think this will work the buttons in the ribbon, but the old command bar still exists on the Developer ribbon
Public Sub reenableOacsbuttons()
Dim c As Object
For Each c In FindCommandBar("OACS").Controls
c.Enabled = True
Next c
End Sub
Put the right obviousness tatement in the rejection
Public Function isPreAIA()
isPreAIA = InStr(ActiveDocument.Range.Text, "The present application is being examined under the pre-AIA first to invent provisions") > 0
End Function
Public Function isAIA()
isAIA = InStr(ActiveDocument.Range.Text, "The present application, filed on or after March 16, 2013, is being examined under the first inventor to file provisions of the AIA") > 0
End Function
Public Sub ItWouldHave()
Dim aia As Boolean, preaia As Boolean
aia = isAIA
preaia = isPreAIA
Dim res As VbMsgBoxResult
If (aia And preaia) Or (Not aia And Not preaia) Then
res = MsgBox("Is case AIA?", vbYesNoCancel, "It would have...")
If res = vbYes Then
aia = True
preaia = False
ElseIf res = vbNo Then
preaia = True
aia = False
ElseIf res = vbCancel Then
Exit Sub
Else
Err.Raise vbError + 1, , "I can't program"
End If
End If
Dim txt As String
If aia Then txt = "It would have been obvious to one of ordinary skill in the art before the effective filing date of the claimed invention to"
If preaia Then txt = "It would have been obvious to one of ordinary skill in the art at the time of the invention to"
Selection.InsertAfter txt
Selection.Collapse WdCollapseDirection.wdCollapseEnd
End Sub
Tuesday, March 3, 2015
Lock Pinned Tabs
Here's the way I use my web browsers. I pin google calendar and gmail. But I don't ever want to close them or navigate away. Tab Mix Plus is great for this, for firefox, but it's a bit of a hog. Firefox also has the setting to always open typed URLs in a new window, which would really solve all the problems for me, but I'm currently migrating to Chrome, and Chrome doesn't have the option. I was looking into writing my own extension to do that, but I really didn't want to go down that rabbit hole. First I'd have to learn it. Plus, I wasn't really sure it was feasible. For my usage, which is two pinned tabs, I had a better idea. It's not ideal, but I made a bookmarklet that will "lock" page . I think this only really works because of how google's apps navigate within their own window, but it works for my use case.
Lock Page
Lock Page
Thursday, December 4, 2014
WRITE_SECURE_SETTINGS on kitkat 4.4
I recently updated my android to a Kitkat rom, and to my dismay, my car dock app, Car Dock Home v3 no longer turned on my GPS. It only brought up the location settings page, and also didn't turn it off when undocking. Apparently this is by design (see below). Now that author has a separate app that manages car dock settings, but I think he baked most features from that into the dock app. ,From the settings app page:
Check GPS Enabled – If the GPS is not enabled upon docking, try to enable it in the secure settings, if that doesn’t work, show the user the Location & Security settings screen.I thought at first secure settings meant the Xposed module, but no it means the way android firmware apps (i.e. system apps) do it which is to use the permission WRITE_SECURE_SETTINGS and do something in the API (I didn't look in to how). The point is that non-system apps can't acquire this permission. So the app should have worked fine if I made it a system app. I never even noticed this becuase
There is also a known exploit to enable GPS using the back end of the power controls widget. I’ve taken advantage of that in the latest releases of this app. It will eventually fail when Google patches it up. The above ‘system app’ technique should still work in that event.So I guess this was patched, but alas, moving it to the /system/app didn't help. The solution was to put it in the new poorly documented /system/priv_app folder. Apparently, apps that previously needed to be converted to system apps to get some permission, now need to be in that folder.
Hopefully this helps someone else get a previously working app functioning.
Friday, March 8, 2013
Outlook to Ical and google
So I'm trying to make it so that my wife can see my calendar which I use at work. This was more difficult then I thought. Biggest problem was the work computer. Second was Microsoft and/or Google's messed up ical implementations. The automated publish options didn't work for me because i couldn't do the whole calendar, and publishing to CalDav didn't work, probably because of the proxy firewall. I could publish to Office but then you can only really see it with Outlook, and I wanted to use google.
Ok so as far as problems normal people might have, they involve the ical file. For extra joy, Google doesn't tell you what the problem is. Since I only got it to work once the this validator passed my file, I assume Google also uses ical4j. Microsoft's main problem was that when publishing events with a timezone, my timezone didn't have a label (e.g. GMT, EST EDT). Even after giving it one in settings it wouldn't export the timezone with an TZID identifier. It just said "TZID:". Interestingly this didn't cause the error, it was when the parser tried to read a time stamp that looked like "TZID=:20130101000000" (rather than "TZID=timezone:2013..."). Having no characters between the = and : caused the parser to pick up a null rather than an empty string, so I didn't even get friendly error messages to help me figure this out. The other problem is how Microsoft wraps long lines. ical files have to be a certain line width. lines are terminated with CRLF and then the next line starts with one space or a tab. MS uses tabs. Both the validator and google didn't like this, but AFAIK MS is correct in doing that. Running the file through simple search and replaces fixed these problems.
The next big question was where to put this file. My work computer is locked down and the proxy blocks most file storage sites. Windows 7 doesn't come with Web Folders. These can refer to the WebDAV folders or the frontpoint server extension version. Comcast which I used to use, uses only FPSE web folders. FTP upload was blocked (mostly, more on that later). Because of this I'd been using MS SkyDrive for online files. But both that and Google Drive don't give you direct dl links, so GCal wouldn't be able to parse it.
Icalx.com looked promising, I think I got a simple HTTP PUT to upload the file a couple of times with a firefox extension. But doing it from my own program was another story. I have a lot of trouble automating the web through my work proxy. The only way I usually have success is to use the IE browser itself through MS Internet Controls (SHDocVw and ieframe.dll). Especially when I need to authenticate site and the proxy, I just can't do it. WinHTTP, MSXML, WebRequest, it just never works, especially if it's anything other than a GET. So FTP is blocked from uploading, but on Windows firewall. So if the program has access already, you can do it. ftp.exe... blocked, the only thing that had access was IE. And the only way I could figure out how to upload was with the FTP Explorer view. After trying Scripting.FileSystemObject, I realized there was another COM library, shell32, Shell Automation. Most of the documentation for this is about using the shell to zip and unzip files, but you can use for http also. There are a few quirks. The best of which is that none of the flags for CopyHere work. Which means no overwriting files, no hiding progress bars. And CopyHere is asyncronous but with no way to get progress or block. Now windows firewall only blocks some ftp commands. So I could use FTPWebRequest to delete the file, without authentication problems, and also use it to check the modification date on the file to see when the upload was done.
Not very pretty or efficient, but it finally works. Hopefully she looks at it.
See what I did
Ok so as far as problems normal people might have, they involve the ical file. For extra joy, Google doesn't tell you what the problem is. Since I only got it to work once the this validator passed my file, I assume Google also uses ical4j. Microsoft's main problem was that when publishing events with a timezone, my timezone didn't have a label (e.g. GMT, EST EDT). Even after giving it one in settings it wouldn't export the timezone with an TZID identifier. It just said "TZID:". Interestingly this didn't cause the error, it was when the parser tried to read a time stamp that looked like "TZID=:20130101000000" (rather than "TZID=timezone:2013..."). Having no characters between the = and : caused the parser to pick up a null rather than an empty string, so I didn't even get friendly error messages to help me figure this out. The other problem is how Microsoft wraps long lines. ical files have to be a certain line width. lines are terminated with CRLF and then the next line starts with one space or a tab. MS uses tabs. Both the validator and google didn't like this, but AFAIK MS is correct in doing that. Running the file through simple search and replaces fixed these problems.
The next big question was where to put this file. My work computer is locked down and the proxy blocks most file storage sites. Windows 7 doesn't come with Web Folders. These can refer to the WebDAV folders or the frontpoint server extension version. Comcast which I used to use, uses only FPSE web folders. FTP upload was blocked (mostly, more on that later). Because of this I'd been using MS SkyDrive for online files. But both that and Google Drive don't give you direct dl links, so GCal wouldn't be able to parse it.
Icalx.com looked promising, I think I got a simple HTTP PUT to upload the file a couple of times with a firefox extension. But doing it from my own program was another story. I have a lot of trouble automating the web through my work proxy. The only way I usually have success is to use the IE browser itself through MS Internet Controls (SHDocVw and ieframe.dll). Especially when I need to authenticate site and the proxy, I just can't do it. WinHTTP, MSXML, WebRequest, it just never works, especially if it's anything other than a GET. So FTP is blocked from uploading, but on Windows firewall. So if the program has access already, you can do it. ftp.exe... blocked, the only thing that had access was IE. And the only way I could figure out how to upload was with the FTP Explorer view. After trying Scripting.FileSystemObject, I realized there was another COM library, shell32, Shell Automation. Most of the documentation for this is about using the shell to zip and unzip files, but you can use for http also. There are a few quirks. The best of which is that none of the flags for CopyHere work. Which means no overwriting files, no hiding progress bars. And CopyHere is asyncronous but with no way to get progress or block. Now windows firewall only blocks some ftp commands. So I could use FTPWebRequest to delete the file, without authentication problems, and also use it to check the modification date on the file to see when the upload was done.
Not very pretty or efficient, but it finally works. Hopefully she looks at it.
See what I did
Thursday, March 7, 2013
Simple way to save Password in a settings file.
/// <summary>
/// Description of Settings.
/// </summary>
public class Settings:ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
public Settings():base()
{
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute("false")]
public bool PASS_SET {
get { return (bool)this["PASS_SET"]; }
private set { this["PASS_SET"] = value; }
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute("")]
/// <summary>
/// <returns> null if !PASS_SET</returns>
/// </summary>
public string Password {
get {
return (PASS_SET)?ToInsecureString(DecryptString(this["Password"].ToString())):null;}
set { this["Password"] = EncryptString(ToSecureString(value)); PASS_SET=true; }
}
static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Bumblebee Tuna, I can see your balls!");
public static string EncryptString(System.Security.SecureString input)
{
byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)),
entropy,
System.Security.Cryptography.DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
public static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
Convert.FromBase64String(encryptedData),
entropy,
System.Security.Cryptography.DataProtectionScope.CurrentUser);
return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
public static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
public static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
}
Subscribe to:
Comments (Atom)